package com.huitone.smspfm.core.smscallltest;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import com.bin.common.utils.DateTimeUtils;
import com.bin.common.utils.SerialUtils;
import com.bin.common.utils.StringUtils;
import com.huitone.smspfm.context.utils.ContextUtils;
import com.huitone.smspfm.core.config.AppStaticConfigs;
import com.huitone.smspfm.core.wransms.SmsWarnRecvMessage;
import com.huitone.smspfm.core.wransms.WranSmsSocketTask;
import com.huitone.smspfm.dao.oracle.SmsCallTestDao;
import com.huitone.smspfm.dao.oracle.SmsSendRecordDao;
import com.huitone.smspfm.dao.oracle.entity.SmsCallTest;
import com.huitone.smspfm.dao.oracle.entity.SmsSendRecord;
import com.huitone.smspfm.dao.oracle.entity.WarnRecv;
import com.huitone.smspfm.logger.ExtLogger;
import com.huitone.smspfm.model.SmsEntityForMt;
import com.huitone.smspfm.redis.pipeline.PipelineOpts.ABExcuteCommands;
import com.huitone.smspfm.task.GetPriListLengthTask;

public class SmsCallScanTask extends Thread {
	
	private static final ExtLogger logger = ExtLogger.create(SmsCallScanTask.class);
	private static SimpleDateFormat SDF = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
	
	private boolean keepGoing = true;
	private boolean toSleep = true;
	private long sleepTime = 1000L;
	private int currMinute = -1;
	private int currScanReportTime = -1;
	
	public boolean isKeepGoing() {
		return keepGoing;
	}

	public void setKeepGoing(boolean keepGoing) {
		this.keepGoing = keepGoing;
	}

	@Override
	public void run() {
		while (keepGoing && !this.isInterrupted()) {
			if (AppStaticConfigs.smsCallTestOnOff) {
				try {
					toSleep = true;
					int currMinuteTmp = Calendar.getInstance().get(
							Calendar.MINUTE);
					if (currMinuteTmp != currMinute) {// 一分钟只执行一次
						currMinute = currMinuteTmp;
						scanAndSendSms();
						toSleep = false;
					}

					// TODO
					if (currMinute % 30 == 0 && currScanReportTime != currMinute) {// 30分钟扫描一次报告
						currScanReportTime = currMinute;
						long currTime = System.currentTimeMillis();
						scanReport();
						toSleep = false;
					}

				} catch (Exception e) {
					e.printStackTrace();
					toSleep = true;
				}
			} else {
				toSleep = true;
			}
			try {
				if (toSleep) {
					Thread.sleep(sleepTime);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
		
		logger.info("拔测任务已经退出！");

	}
	
	private void scanReport() {
		//扫描redis中的拔测短信列表
//		logger.info("拔测短信报告扫描　"+ new Date());
		
		RedisScript<List> script = new DefaultRedisScript<List>(AppStaticConfigs.luaGetCallTestListKeys, List.class);
		List<String> luaKeys = new ArrayList<String>();
		luaKeys.add(AppStaticConfigs.isMcallTestSend);
		
		List<String> keys = AppStaticConfigs.scriptOpts3.getList(script, luaKeys, 1000+"");
		List<byte[]> saveKeys = new ArrayList<byte[]>();
		List<String> wranKeys = new ArrayList<String>();
		//查询数据库
		List<SmsSendRecord> smsRecord = new ArrayList<SmsSendRecord>();
		if(keys != null && keys.size() > 0){
			for(String key : keys){
				List<String> keyList = StringUtils.splitToList(key, ":");
				if (keyList != null && keyList.size() >= 3) {
					String seqNum = keyList.get(0);
					String phone = keyList.get(1);
					String gateLinkId = keyList.get(2);
					SmsSendRecord sms = ContextUtils.getBean2(SmsSendRecordDao.class).getObjForDay(seqNum, phone);
					if(sms == null){
						saveKeys.add(AppStaticConfigs.stringRedisSerializer.serialize(key));
					} else {
						if(! StringUtils.equals("0", sms.getSendCode())){//失败发告警短信
							wranKeys.add(key);
						} 
						
					}
				}
			}
		}
		
		//未出结果的键保存至缓存中
		if(saveKeys.size() > 0){
			
			byte[][] bts = new byte[saveKeys.size()][];
			for(int i  = 0; i < saveKeys.size() ; i++){
				bts[i] = saveKeys.get(i);
			}
			 AppStaticConfigs.pipelineOpts3.save(new ABExcuteCommands() {

				@Override
				public void excute(RedisConnection connection) {		
					
						connection.lPush(AppStaticConfigs.isMcallTestSendB,bts);
					
				}
				 
			});
		}
		
		//需要发告警短信的手机号
		if(wranKeys.size() > 0){
			
			for (String wranKey : wranKeys) {
				List<String> keyList = StringUtils.splitToList(wranKey, ":");
				if (keyList != null && keyList.size() >= 3) {
					String seqNum = keyList.get(0);
					String phone = keyList.get(1);
					String gateLink = keyList.get(2);
					// 写告警短信
					List<WarnRecv> users = AppStaticConfigs.warnRecvList;
					String mContent = AppStaticConfigs.smsTemplateMap.get(
							AppStaticConfigs.Const.SMS_TEMPLATE_TYPE_BT)
							.getSmsContent();
					mContent =  StringUtils.replace(mContent,"[time]",DateTimeUtils.dateToStr(new Date(),"yyyy/MM/dd HH:mm:ss"));
					mContent =  StringUtils.replace(mContent,"[userNum]",phone);
					mContent =  StringUtils.replace(mContent,"[gateLinkId]",gateLink);
					SmsWarnRecvMessage message = new SmsWarnRecvMessage(users,
							mContent,AppStaticConfigs.Const.SMS_TEMPLATE_TYPE_BT);

					WranSmsSocketTask.msgQueue.offer(message);
//					logger.info("发送拔测失败告警短信 ：" + message.toString());
				}
			}
		}
				
	}
	
	protected SmsCallTest toCallTestEntity(String recId,String sendResult,String smSeq) {
		SmsCallTest result = new SmsCallTest();
		result.setRecId(recId);
		result.setSendResult(sendResult);
		result.setSmSeq(smSeq);
		return result;
	}




	private void scanAndSendSms() {
		logger.info("拔测任务开始执行！");
		Set<String> set = AppStaticConfigs.smsCallTestSentMap.get(currMinute);
		if( set.size() > 0){
			//发送短信并记录
			for(String sms : set){
				List<String> list = StringUtils.splitToList(sms, ",");
				String gateId = list.get(0);
				String phone = list.get(1);
				//TODO 检查用户 是否可以使用该通道发送短信。
				if(! checkUserGateIsOk(phone,gateId)){
					continue;
				}
				String priName = getPriQueueName(gateId);
				String svrName = AppStaticConfigs.systemSmsSendSvrNode;
				String modeName = AppStaticConfigs.appName;
				String smType = "1";
				String sendPort = AppStaticConfigs.systemSmsSendSendPort;
				String content = AppStaticConfigs.smsCallTest.getTestContent();
				content = StringUtils.replace(content, "[userNum]", " "+phone+" "); 
				content = StringUtils.replace(content, "[time]", " "+SDF.format(new Date())+" ");
				content = StringUtils.replace(content, "[gateLinkId]", " "+gateId+" ");
				
				
				String serialSegment= AppStaticConfigs.systemSmsSendCode 
							+","+ DateTimeUtils.dateToStr(new Date(),"MMddHHmmss" 
							+"," + StringUtils.toString(SerialUtils.getSerial()));
				
				String serviceCode = AppStaticConfigs.systemSmsSendServiceCode;
				List<String> entityList = new ArrayList<String>();
				entityList.add(0,svrName);				
				entityList.add(1,serviceCode);				
				entityList.add(2,smType);
				entityList.add(3,phone);
				entityList.add(4,content);
				entityList.add(5,"1");//短信类型
				entityList.add(6,DateTimeUtils.dateToStr(new Date(), "yyyyMMddHHmmss"));				
				entityList.add(7,modeName);			
				entityList.add(8,sendPort);				
				entityList.add(9,serialSegment);
				entityList.add(10,"");//提交时间
				entityList.add(11,"");//结果时间
				entityList.add(12,"");//旧平台编码
				entityList.add(13,serialSegment.replaceAll(",", ""));//旧平台序号
				entityList.add(14,"");//未知
				
				SmsEntityForMt smsEntity  = SmsEntityForMt.parse(entityList);
				//增加通道ID配置
				smsEntity.setGateLinkId(gateId);
				Map<byte[],byte[]> smsMap = smsEntity.getMapB();
				String seqNum = smsEntity.getSerialno() + ":" + smsEntity.getPhoneNumber();
				//加入优先级队列中，表示短信发送
				AppStaticConfigs.pipelineOpts3.save(new ABExcuteCommands() {
					@Override
					public void excute(RedisConnection connection) {
						connection.hMSet(AppStaticConfigs.stringRedisSerializer.serialize(AppStaticConfigs.pSMCacheHash + ":" + seqNum), smsMap);//SMINFO
						//SMCache
						connection.lPush(AppStaticConfigs.stringRedisSerializer.serialize(priName),AppStaticConfigs.stringRedisSerializer.serialize(seqNum));//PriList
						GetPriListLengthTask.priListLength.put(priName, StringUtils.toLong(GetPriListLengthTask.priListLength.get(priName)) + 1);//LENGTH	
						//序列号保存在缓存中
						connection.lPush(AppStaticConfigs.isMcallTestSendB, AppStaticConfigs.stringRedisSerializer.serialize(seqNum +":"+gateId));																
					}
					
				});
				

			}
		}
		logger.info("拔测任务执行完毕！");
	}
	
	private boolean checkUserGateIsOk(String phone, String gateId) {
		boolean result = false;
		logger.info("匹配号段 ： "+phone + " 通道ID: "+gateId);
		int length = phone.length();
		for (int i = length; i > 2; i--) {
			// 检查手机可用的运营商
			String phoneTmp = StringUtils.substring(phone, 0, i);
			// 检查gateId属于哪个运营商
			if (AppStaticConfigs.phoneMobileCorpMap.containsKey(phoneTmp)) {
				
				String mobileCorp = AppStaticConfigs.phoneMobileCorpMap
						.get(phoneTmp);
				logger.info("已找到号段路由 ！     号段： "+phoneTmp+" 运营商： "+ mobileCorp +" 通道ID: "+gateId);
				if (AppStaticConfigs.gateMobileCorpSet.containsKey(mobileCorp)) {
					result = AppStaticConfigs.gateMobileCorpSet.get(mobileCorp)
							.contains(gateId);
					logger.info("已找到号段路由和运营商通道表 ！     号段： "+phoneTmp+" 运营商： "+ mobileCorp +" 通道ID: "+gateId+" 检测结果：" +result);
					break;
				}
			}
		}
		return result;
	}

	private String getPriQueueName(String gateLinkId) {
		String result = null;
		String scanKey = AppStaticConfigs.iSMPriListNamesSet;
		
		RedisScript<List> script = new DefaultRedisScript<List>(AppStaticConfigs.luaGetPriListName, List.class);
		
		List<String> keys = new ArrayList<>();
		keys.add(scanKey);
		
		List<String> list = AppStaticConfigs.scriptOpts3.getList(script, keys, "1000");
		long length = -1L;
		if(list != null && list.size() > 0){
			for (int i = 0; i < list.size(); i++) {
				String priListName = list.get(i);
				String gateIdKey = StringUtils.splitThRIndex(priListName, ":", 1);
				if(!StringUtils.equals(gateLinkId, gateIdKey)){
					continue;
				}
				long listLength = -1L;
				if(GetPriListLengthTask.priListLength.containsKey(priListName)){
					listLength = GetPriListLengthTask.priListLength.get(priListName);
				}
				if (listLength != -1) {
					if (length == -1) {
						length = listLength;
						result = priListName;
					} else {
						if (length > listLength) {
							length = listLength;
							result = priListName;
						}
					}
				}
			}
		}
		
		if(result == null){//主动生成一个优先级队列　，　[SM:GATE_LINK_ID:999:LIST]
//			String priListNames = "SM:"+gateLinkId+":Pri:999:List";
			String priListNames = "SM:"+gateLinkId+":Cache:999:List";
			result = priListNames;
//			GetPriListLengthTask.priListLength.put(result,1L); 未添加，　不能使用
			AppStaticConfigs.pipelineOpts.save(new ABExcuteCommands() {
				@Override
				public void excute(RedisConnection connection) {
					
					connection.sAdd(AppStaticConfigs.iSMPriListNamesSetB, AppStaticConfigs.stringRedisSerializer.serialize(priListNames));
				}				
			});
			
		}
		return result;
	}

	@Override
	public void destroy() {
		setKeepGoing(false);
		this.interrupt();
	}
	
	
	
}
